function initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE){
    // 创建着色器
    // 创建顶点着色器
    let vertexShader = gl.createShader(gl.VERTEX_SHADER);
    // 创建片元着色器
    let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

    // 着色器 指定 源码
    // 指定顶点着色器源码
    gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE);
    // 指定偏远着色器源码
    gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE);

    // 编译着色器
    gl.compileShader(vertexShader);
    gl.compileShader(fragmentShader);

    // 创建一个程序对象 关联webgl和javascript
    let program = gl.createProgram();

    // 给程序对象指定它使用的两个着色器
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);

    // 将 程序对象 和 webgl关联
    gl.linkProgram(program)

    // 使用程序对象
    gl.useProgram(program)

    return program
}

// 平移矩阵
function getTranslateMatrix(x=0,y=0,z=0){
    // 通过 new Float32Array 创建一个矩阵  这个矩阵是推理出来的
    return new Float32Array([
        1.0, 0.0, 0.0, 0.0,
        0.0, 1.0, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,
        x, y, z, 1.0
    ])
}
// 缩放矩阵
function getScaleMatrix(x=1,y=1,z=1){
    // 通过 new Float32Array 创建一个矩阵  这个矩阵是推理出来的
    return new Float32Array([
        x  , 0.0, 0.0, 0.0,
        0.0, y  , 0.0, 0.0,
        0.0, 0.0, z  , 0.0,
        0.0, 0.0, 0.0, 1.0
    ])
}
// 绕Z轴旋转 的 旋转矩阵
function getRotateMatrix(deg){  // 绕Z轴旋转的
    // 通过 new Float32Array 创建一个矩阵  这个矩阵是推理出来的
    return new Float32Array([
        Math.cos(deg),  Math.sin(deg),  0.0, 0.0,
        -Math.sin(deg), Math.cos(deg), 0.0, 0.0,
        0.0,            0.0,            1.0, 0.0,
        0.0,            0.0,            0.0, 1.0
    ])
}

// 矩阵复合函数
function mixMatrix(A,B){
    // 16 是16个参数
    let result = new Float32Array(16);

    for(let i=0;i<4;i++){
        result[i] = A[i]*B[0] + A[i+4]*B[1] + A[i+8]*B[2] + A[i+12]*B[3]
        result[i+4] = A[i]*B[4] + A[i+4]*B[5] + A[i+8]*B[6] + A[i+12]*B[7]
        result[i+8] = A[i]*B[8] + A[i+4]*B[9] + A[i+8]*B[10] + A[i+12]*B[11]
        result[i+12] = A[i]*B[12] + A[i+4]*B[13] + A[i+8]*B[14] + A[i+12]*B[15]
    }

    return result;
}


// 归一化函数
function normalized(arr){
    let sum = 0;

    for(let i=0; i<arr.length;i++){
        sum += arr[i] * arr[i]
    }
    // sum的开平方
    const middle = Math.sqrt(sum)
    // 这样就实现了 将数组内的每一个数 都归一化到0-1间内
    for(let i=0; i<arr.length;i++){
        arr[i] = arr[i]/middle;
    }
}

// 叉积函数 作用是 获取法向量
function cross(a, b) {
    return new Float32Array([
        a[1] * b[2] - a[2] * b[1],
        a[2] * b[0] - a[0] * b[2],
        a[0] * b[1] - a[1] * b[0],
    ])
}

// 点积函数 获取投影长度
function dot(a, b) {
    return  a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}

// 向量差
function minus(a,b) {
    return new Float32Array([
        a[0] - b[0],
        a[1] - b[1],
        a[2] - b[2],
    ])
}

// 视图矩阵获取
function getViewMatrix(eyex, eyey, eyez, lookAtx, lookAty, lookAtz, upx, upy, upz){
    // 视点
    let  eye = new Float32Array([eyex, eyey, eyez])
    // 目标点
    let  lookAt = new Float32Array([lookAtx, lookAty, lookAtz])
    // 上方向
    let  up = new Float32Array([upx, upy, upz])

    // z轴 最好实现， 视点和目标点 确定
    let z = minus(eye, lookAt);

    // 在使用这些数据之前 需要先归一化
    normalized(z);
    normalized(up);

    // 然后确定x轴， 因为x轴是同时 垂直于z轴和上方向的
    let x = cross(z, up); // 通过叉积函数

    normalized(x);
    // 确定Y轴
    let y = cross(x, z);

    // 视图矩阵 4*4 的矩阵 所以 要补齐后面
    return new Float32Array([
        x[0],           y[0],           z[0],           0,
        x[1],           y[1],           z[1],           0,
        x[2],           y[2],           z[2],           0,
        -dot(x,eye),    -dot(y,eye),    -dot(z,eye),    1,
    ])
}

// 用来获取 正射投影矩阵 参数 左面 右面 上面 下面 近 远
function getOrtho(l, r, t, b, n, f) {
    return  new Float32Array([
        2/(r-l),     0,             0,            0,
        0,           2/(t-b),       0,            0,
        0,           0,             -2/(f-n),     0,
        -(r+l)/(r-l), -(t+b)/(t-b), -(f+n)/(f-n), 1

    ])
}


// 创建透视投影矩阵
// 视角 宽高比 far near
function getPerspective(fov, aspect, far, near){
    // 需要将角度 转为 弧度
    fov = fov * Math.PI / 180;
    return  new Float32Array([
        1/(aspect*Math.tan(fov / 2)), 0, 0, 0,
        0, 1/(Math.tan(fov/2)),0,0,
        0,0,-(far+near)/(far-near),-(2*far*near)/(far-near),
        0,0,-1,0,
    ])
}
